package ar.com.coonocer.joy.mdg.util.reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class ReflectionUtil {

	private static Log logger = LogFactory.getLog(ReflectionUtil.class);

	public static Set<Method> findMethod(Class<?> targetClass, String methodName, int parameterCount) {
		Set<Method> list = new HashSet<Method>();
		//
		do {
			Method[] methods = targetClass.getDeclaredMethods();
			for (int i = 0; i < methods.length; i++) {
				if (methods[i].getName().equals(methodName)) {
					if (methods[i].getParameterTypes().length == parameterCount) {
						list.add(methods[i]);
					}
				}
			}
			targetClass = targetClass.getSuperclass();
		} while (targetClass != null);
		//
		return list;
	}

	public static Object invokeMethod(Object object, Method method, Object[] params) {
		try {
			return method.invoke(object, params);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException("Error invoking method: " + object.getClass().getSimpleName() + "." + method.getName() + "(" + Arrays.asList(params) + ")", e);
		} catch (IllegalAccessException e) {
			throw new RuntimeException("Error invoking method: " + object.getClass().getSimpleName() + "." + method.getName() + "(" + Arrays.asList(params) + ")", e);
		} catch (InvocationTargetException e) {
			throw new RuntimeException("Error invoking method: " + object.getClass().getSimpleName() + "." + method.getName() + "(" + Arrays.asList(params) + ")", e);
		}
	}

	public static Object getAttributeValue(Object currentObject, String attName) {
		String methodName = generateMethodName("get", attName);
		Set<Method> methods = ReflectionUtil.findMethod(currentObject.getClass(), methodName, 0);
		//
		if (methods.size() == 0) {
			logger.warn("Getter method not found: " + currentObject.getClass().getSimpleName() + "." + methodName);
		} else { //1
			//
			Method method = methods.iterator().next();
			try {
				return ReflectionUtil.invokeMethod(currentObject, method, new Object[] {});
			} catch (RuntimeException e) {
				logger.warn("Setting attribute: " + currentObject.getClass().getSimpleName() + "." + attName);
				e.printStackTrace();
			}
		}
		return null;
	}

	//Genera nombre del getter o setter para el atributo
	public static String generateMethodName(String prefix, String attName) {
		String methodName;
		if (attName.length() == 1) {
			methodName = prefix + attName.toUpperCase();
		} else {
			methodName = prefix + attName.substring(0, 1).toUpperCase() + attName.substring(1);
		}
		return methodName;
	}
}
